import glob
import os.path
import subprocess

try:
    import _winreg
except:
    _winreg = None

import os_helpers

class LocalHost(object):
    """
    Interface to the local host.
    """

    if _winreg:
        HKLM = _winreg.HKEY_LOCAL_MACHINE
        HKCU = _winreg.HKEY_CURRENT_USER
        HKCR = _winreg.HKEY_CLASSES_ROOT
    else:
        # Define useless values; the actual winreg_... calls will fail.
        HKLM = 0
        HKCU = 0
        HKCR = 0
    
    def __init__(self, user_dir):
        self.os_name = os.name
        self.os_name_list = os_helpers.name_list
        self.description = None
        self._default_path = os.environ['PATH']
        
        # As of August 2012, we expect a few temporary files, frequently used,
        # so maintain our own temporary directory instead of using the OS's.
        self.work_dir = os.path.join(user_dir, 'temp')
        os_helpers.mkdir_p(self.work_dir)

    def call_gui(self, *args):
        """
        Spawns *args as a background GUI process (similar to Subprocess.call).
        
        Some host interfaces may not support this; callers should use hasattr
        to check.
        
        May throw exceptions.
        """
        if type(args[0]) == str:
            cmdline = args[0]
        else:
            cmdline = " ".join(*args)
        subprocess.Popen(cmdline, shell=True)

    def chdir(self, path):
        return os.chdir(path)

    def environ_prepend_path(self, path):
        """
        Prepends path to the beginning of the PATH environment variable.
        """
        if self.os_name == 'nt':
            path_sep = ';'
        else:
            path_sep = ':'
        os.environ['PATH'] = path_sep.join([path, os.environ['PATH']])

    def environ_reset_path(self):
        """
        Resets the PATH environment variable to the values it had at startup.
        """
        os.environ['PATH'] = self._default_path

    def file_write(self, path, mode, data):
        """
        Writes data to the given path, using the given mode.
        """
        with open(path, mode) as f:
            f.write(data)

    def getenv(self, varname, value=None):
        """
        As os.getenv, or reading a value from os.environ.  An os.environ-like
        interface is not currently exposed due to the additional complexity.
        """
        return os.getenv(varname, value)

    def getcwd(self):
        return os.getcwd()

    def glob(self, pathname):
        return glob.glob(pathname)

    def listdir(self, path):
        return os.listdir(path)

    def path_basename(self, path):
        return os.path.basename(path)

    def path_dirname(self, path):
        return os.path.dirname(path)

    def path_exists(self, path):
        return os.path.exists(path)

    def path_join(self, *args):
        return os.path.join(*args)

    def popen(self, *args, **kwargs):
        """
        Spawns *args as a process (just like subprocess.Popen) and returns a
        subprocess.Popen-like object.
        
        NOTE: subprocess.Popen is probably much more complicated than we want
        to implement for future host interfaces; right now, only the communicate
        and wait methods and the returncode attribute of the returned object
		should be used.
        
        NOTE: Other implementations must support subprocess.PIPE and
        stderr=subprocess.STDOUT.
        """
        if not kwargs.has_key('stdin'):
            kwargs['stdin'] = subprocess.PIPE
        if not kwargs.has_key('stdout'):
            kwargs['stdout'] = subprocess.PIPE
        if not kwargs.has_key('stderr'):
            kwargs['stderr'] = subprocess.PIPE
        return subprocess.Popen(*args, **kwargs)

    def popen_in_console(self, args):
        """
        Spawns args (which should be either a string or a sequence of program
        arguments, just like subprocess.Popen's first parameter) as a process in
        its own console or terminal window.
        """
        
        # NOTE: We don't properly escape arguments; given our current usage,
        # that's hopefully okay...
        # TODO: How to undo redirection that's performed by being run within Eclipse?
        # As it is, we can't run Python scripts from Eclipse's debugger...
        # TODO: Escape arguments
        
        if type(args) is str:
            args = [ args]
             
        if 'nt' in self.os_name_list:
            # Use "start" to force the process to start in a new console window,
            # but "start" is a cmd.exe builtin, so we have to run cmd first.
            # There has GOT to be an easier way of doing this...
            sub_args = []
            sub_args.extend(args)
            sub_args.extend(['&', 'pause'])
            console_args = [ 'cmd', '/c', 'start', 'cmd', '/c', ' '.join(sub_args) ]
        elif self.os_name == 'posix':
            # TODO: Test
            # TODO: Alternate terminal?
            console_args = [ 'gnome-terminal', '-e', 
                             'bash -c "%s; read -p \'Press any key to continue\'"' % " ".join(args) ]
        # TODO: Mac
        subprocess.Popen(console_args)

    def putenv(self, varname, value):
        """
        As os.putenv, or assigning a value to os.environ.  An os.environ-like
        interface is not currently exposed due to the additional complexity.
        """
        os.environ[varname] = value

    def winreg_enum_keys(self, key, sub_key):
        """
        Enumerates all registry keys under key\subkey.
        
        key should be HKCU or HKLM.
        
        Throws an exception if this is not an NT host.
        """
        with _winreg.OpenKey(key, sub_key) as r:
            result = []
            i = 0
            while True:
                try:
                    result.append(_winreg.EnumKey(r, i))
                    i += 1
                except WindowsError:
                    break
            return result

    def winreg_query_value(self, key, sub_key, value_name):
        """
        Queries a registry value.  Similar to _winreg's QueryValue and
        QueryValueEx.
        
        The current implementation does not return the type as 
        _winreg.QueryValueEx does.
        """
        with _winreg.OpenKey(key, sub_key) as r:
            result = _winreg.QueryValueEx(r, value_name)[0]
            if type(result) == unicode:
                return result.encode()
            else:
                return result

    def get_file_version(self, path):
        if hasattr(os_helpers, 'get_file_version'):
            try:
                return os_helpers.get_file_version(path)
            except:
                pass
        # If we don't have a get_file_version function, or if it fails, then
        # give up and return a default string.
        return "unknown"
